package com.nineclock.approve.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.nineclock.approve.dto.*;
import com.nineclock.approve.mapper.ApproveDefinitionMapper;
import com.nineclock.approve.pojo.ApproveDefinition;
import com.nineclock.approve.service.ActivitiService;
import com.nineclock.approve.service.ApproveDefinitionService;
import com.nineclock.approve.utils.ApproveExtendsUtils;
import com.nineclock.common.enums.ResponseEnum;
import com.nineclock.common.exception.NcException;
import com.nineclock.common.threadlocal.CurrentUserHolder;
import com.nineclock.common.utils.BeanHelper;
import com.nineclock.common.utils.JsonUtils;
import com.nineclock.common.utils.UUIDUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Transactional
public class ApproveDefinitionServiceImpl implements ApproveDefinitionService {

    @Autowired
    private ApproveDefinitionMapper definitionMapper;

    @Override
    public List<ApproveGroupDefinitionDto> queryApproveDefintion() {
        List<ApproveGroupDefinitionDto> groupDefinitionDtos = new ArrayList<>();

        //获取当前企业的ID
        Long companyId = CurrentUserHolder.get().getCompanyId();

        //组装条件, 查询流程定义列表
        LambdaQueryWrapper<ApproveDefinition> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ApproveDefinition::getCompanyId, companyId);//企业ID
        wrapper.eq(ApproveDefinition::getIsValid, "1");//状态有效

        List<ApproveDefinition> definitionList = definitionMapper.selectList(wrapper);

        //遍历流程定义的集合 , 组装数据, 并返回
        if(CollectionUtil.isNotEmpty(definitionList)){
            Map<String, List<ApproveDefinition>> groupMap = definitionList.stream().collect(Collectors.groupingBy(ApproveDefinition::getGroupType));

            for (String groupType : groupMap.keySet()) {

                ApproveGroupDefinitionDto groupDefinitionDto = new ApproveGroupDefinitionDto();
                groupDefinitionDto.setGroupType(groupType);
                groupDefinitionDto.setDefinitionList(groupMap.get(groupType));

                groupDefinitionDtos.add(groupDefinitionDto);
            }
        }
        return groupDefinitionDtos;
    }


    @Autowired
    private ActivitiService activitiService;

    @Override
    public void saveApproveDefintion(ApproveDefinitionSaveDto definitionSaveDto) {
        //1. 参数校验
        if(definitionSaveDto == null || definitionSaveDto.getTableData() == null ||
                StrUtil.isEmpty(definitionSaveDto.getFlowData()) || definitionSaveDto.getBaseData() == null){
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }

        ApproveDefinitionBaseDataDto baseData = definitionSaveDto.getBaseData();

        if(StrUtil.isEmpty(baseData.getId())) { //如果主键ID不存在, 则执行新增
            //2. 组装流程定义的数据

            //2.1 流程定义的基本数据
            ApproveDefinition approveDefinition = BeanHelper.copyProperties(baseData, ApproveDefinition.class);

            List<AllowUserObjDto> userObjDtoList = baseData.getAllowUserJson();
            approveDefinition.setAllowUserJson(JsonUtils.toString(userObjDtoList));

            //基本属性
            approveDefinition.setCompanyId(CurrentUserHolder.get().getCompanyId()+"");
            approveDefinition.setIsValid("1");//有效
            approveDefinition.setCreateTime(new Date());
            approveDefinition.setUpdateTime(new Date());
            approveDefinition.setDataFrom("1");//1: 自定义流程 , 0: 模板


            //2.2 组装流程表单数据
            List<ApproveDefinitionTableDataDto> tableData = definitionSaveDto.getTableData();
            approveDefinition.setFormJson(JsonUtils.toString(tableData));//表单数据
            approveDefinition.setTableName("flow_"+ UUIDUtils.getUUID());//表单标识

            //记录表单的组件
            List<ColumnObjDto> columnObjDtos = ApproveExtendsUtils.getClolumnListWithFieldKey(definitionSaveDto);
            approveDefinition.setColumns(JsonUtils.toString(columnObjDtos));


            //2.3 组装流程数据
            String flowData = definitionSaveDto.getFlowData();

            //为了后续使用, 每一个节点都需要扩充一个唯一标识 nodeKey ;
            JSONArray jsonArray = JSONUtil.parseArray(flowData);
            ApproveExtendsUtils.expandParamWithNodeKey(jsonArray);

            approveDefinition.setFlowJson(JSONUtil.toJsonStr(jsonArray));

            //3. 将数据插入到数据库
            definitionMapper.insert(approveDefinition); //===========> 组装业务数据, 插入数据库, 目前并没有与 Activiti 关联 ;


            //TODO 将流程设计数据, 动态构建Bpmn , 并将其部署到Activiti
            activitiService.deployProcessToActiviti(approveDefinition);


        }else{//如果存在ID主键, 则执行修改

            //1. 根据ID查询当前流程定义数据
            ApproveDefinition definition = definitionMapper.selectById(baseData.getId());

            //2. 将接收到的参数 , 复制给查询出来的实体
            //2.1 基本信息
            BeanUtil.copyProperties(baseData, definition);

            //2.2 处理allowUserJson
            List<AllowUserObjDto> objDtoList = baseData.getAllowUserJson();
            String allowUserJsonStr = JsonUtils.toString(objDtoList);
            definition.setAllowUserJson(allowUserJsonStr);

            //2.3 表单数据
            List<ApproveDefinitionTableDataDto> tableData = definitionSaveDto.getTableData();
            String tableDataStr = JsonUtils.toString(tableData);
            definition.setFormJson(tableDataStr);

            List<ColumnObjDto> columnObjDtoList = ApproveExtendsUtils.getClolumnListWithFieldKey(definitionSaveDto);
            definition.setColumns(JsonUtils.toString(columnObjDtoList));

            definition.setTableName("flow_"+UUIDUtils.getUUID());

            //2.4 流程设计数据
            String flowData = definitionSaveDto.getFlowData();
            JSONArray jsonArray = JSONUtil.parseArray(flowData);

            ApproveExtendsUtils.expandParamWithNodeKey(jsonArray);
            definition.setFlowJson(JSONUtil.toJsonStr(jsonArray));


            //3. 根据ID更新
            definitionMapper.updateById(definition);



            //TODO 将流程设计数据, 动态构建Bpmn , 并将其部署到Activiti
            //4.1 先删除原有的流程部署
            activitiService.deleteProcessDeployFromActiviti(definition);

            //4.2 再部署新的流程
            activitiService.deployProcessToActiviti(definition);

        }

    }


    @Override
    public ApproveDefinitionResultDto queryDefinitionById(String id) {

        //1. 直接根据主键查询
        ApproveDefinition approveDefinition = definitionMapper.selectById(id);

        //2. 组装结果并返回
        //2.1 基本属性
        ApproveDefinitionBaseDataDto definitionBaseDataDto = BeanHelper.copyProperties(approveDefinition, ApproveDefinitionBaseDataDto.class);

        //组装可以发起该审批实体
        String allowUserJson = approveDefinition.getAllowUserJson();
        List<AllowUserObjDto> allowUserObjDtos = JsonUtils.toList(allowUserJson, AllowUserObjDto.class);
        definitionBaseDataDto.setAllowUserJson(allowUserObjDtos);


        //2.2 表单数据
        String formJson = approveDefinition.getFormJson();
        List<ApproveDefinitionTableDataResultDto> tableDataResultDtos = JsonUtils.toList(formJson, ApproveDefinitionTableDataResultDto.class);


        //2.3 流程设计数据
        String flowJson = approveDefinition.getFlowJson();

        ApproveDefinitionResultDto resultDto = new ApproveDefinitionResultDto();
        resultDto.setBaseData(definitionBaseDataDto).setTableData(tableDataResultDtos).setFlowData(flowJson);

        return resultDto;
    }


}
